/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package net.cjb.malacma.rssfeed.persistence;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import net.cjb.malacma.rssfeed.entity.FeedUrl;
import net.cjb.malacma.rssfeed.entity.Tag;
import net.cjb.malacma.rssfeed.entity.UserContext;
import net.cjb.malacma.rssfeed.persistence.exceptions.IllegalOrphanException;
import net.cjb.malacma.rssfeed.persistence.exceptions.NonexistentEntityException;

/**
 *
 * @author malacma
 */
public class JPAController extends GenericPersistence {

    /**
     * @ SingleTON ;)
     */
    //Sincroniza para obter apenas uma EntityManager
    public static final void persist(Object object) throws Exception {
        EntityManager em = getEntityManager();
        try {
            em.getTransaction().begin();
            em.persist(object);
            em.getTransaction().commit();
        } catch (Exception e) {
            em.getTransaction().rollback();
            try {
                em.getTransaction().begin();
                em.merge(object);
                em.getTransaction().commit();
            } catch (Exception e1) {
                em.getTransaction().rollback();
                throw e1;
            }
        } finally {
            object = null;
            closeEntityManager();
        }
    }

    public static final FeedUrl getLastFeedUrl() throws Exception {
        EntityManager em = getEntityManager();
        FeedUrl fu = null;
        try {
            //em.getTransaction().begin();
            fu = (FeedUrl) em.createNamedQuery("FeedURL.findLastFeed").getSingleResult();
        } catch (Exception e) {
            throw e;
        } finally {
            //closeEntityManager();
            return fu;
        }
    }

    public static UserContext findUserContextByMail(String email) {
        EntityManager em = getEntityManager();
        UserContext u = null;
        try {
            u = (UserContext) em.createNamedQuery("UserContext.findByMail").setParameter("myEmail", email).getSingleResult();
        } finally {
            return u;
        }
    }

    public static List<Tag> findTags(int total) {
        EntityManager em = getEntityManager();
        List<Tag> tags = null;
        try {
            Query q = em.createNamedQuery("Tag.findAll");
            q.setMaxResults(total);
            tags = (List<Tag>) q.getResultList();
        } finally {
            return tags;
        }
    }

    public static final List<FeedUrl> findAllFeedUrl() throws Exception {
        EntityManager em = getEntityManager();
        List<FeedUrl> fu = new ArrayList<FeedUrl>();
        try {
            fu = (List<FeedUrl>) em.createNamedQuery("FeedURL.findAllFeeds").getResultList();
        } finally {
            return fu;
        }
    }

    public static List<FeedUrl> findOffLineFeeds() throws Exception {
        EntityManager em = getEntityManager();
        List<FeedUrl> fu = new ArrayList<FeedUrl>();
        try {
            fu = (List<FeedUrl>) em.createNamedQuery("FeedURL.findOffline").getResultList();
        } finally {
            return fu;
        }
    }

    public static FeedUrl findFeedByTitle(String tile) throws NonexistentEntityException, Exception {
        EntityManager em = getEntityManager();
        FeedUrl fu = new FeedUrl();
        try {
            fu = (FeedUrl) em.createNamedQuery("FeedURL.findByTitle").setParameter("titulo", tile).getSingleResult();
        } catch (Exception e) {
            throw e;
        } finally {
            return fu;
        }
    }

    public static Tag findTagByTitle(String tile) throws NonexistentEntityException, Exception {
        EntityManager em = getEntityManager();
        Tag tag = new Tag();
        try {
            tag = (Tag) em.createNamedQuery("Tag.findByTag").setParameter("txt", tile).getSingleResult();
        } catch (Exception e) {
            tag = null;
            throw e;
        } finally {
            return tag;
        }
    }

    public static void merge(Object f1) throws IllegalOrphanException, Exception {
        EntityManager em = getEntityManager();
        try {
            em.getTransaction().begin();
            em.merge(f1);
            em.getTransaction().commit();
        } catch (Exception e) {
            em.getTransaction().rollback();
            e.printStackTrace();
        } finally {
            closeEntityManager();
        }
    }

    public static void persistTags(FeedUrl feed, String parameter) throws Exception {
        EntityManager em = getEntityManager();
        Scanner sc = new Scanner(parameter);
        HashMap<String, String> mapaTags = new HashMap<String, String>();
        try {
            em.getTransaction().begin();
            feed = (FeedUrl) em.createNamedQuery("FeedURL.findByTitle").setParameter("titulo", feed.getTitulo()).getSingleResult();

            //Monta um mapa com todas as tags
            for (Tag t : feed.getTags()) {
                mapaTags.put(t.getTxt(), t.getId().toString());
            }

            String token = null;

            //Percorre os parâmetros
            while (sc.hasNext()) {

                token = sc.next().toUpperCase();

                Tag t1 = null;
                try {
                    t1 = (Tag) em.createNamedQuery("Tag.findByTag").setParameter("txt", token).getSingleResult();
                } catch (Exception e) {
                    t1 = new Tag();
                    t1.setTxt(token.toUpperCase());
                    em.persist(t1);
                }
                if (!mapaTags.containsKey(token.toUpperCase())) {
                    feed.getTags().add(t1);
                }
            }
            em.merge(feed);
            em.getTransaction().commit();
        } catch (Exception e) {
            em.getTransaction().rollback();
        } finally {
            sc.close();
            sc = null;
            mapaTags.clear();
            mapaTags = null;
            closeEntityManager();
        }

    }

    public static void create(Object o) throws Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            em.persist(o);
            em.getTransaction().commit();
        } finally {
            closeEntityManager();
        }
    }

    public static void edit(Object o) throws NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            o = em.merge(o);
            em.getTransaction().commit();
        } catch (Exception ex) {
            throw new NonexistentEntityException(ex.toString());
        } finally {
            closeEntityManager();
        }
    }

    public static List<?> findlEntities() {
        return findEntities(true, -1, -1);
    }

    public static List<FeedUrl> findCloudEntities(int maxI) {
        EntityManager em = getEntityManager();
        long total = 0;
        List<FeedUrl> l = null;
        try {
//            ((Long) (.getResultList()).int;
            total = ((Long) em.createQuery("select count(o) from FeedUrl as o").getSingleResult()).intValue();
            l = em.createNamedQuery("FeedURL.findAllFeeds").setFirstResult((int) ((total / 2) - maxI)).setMaxResults(maxI).getResultList();
        } finally {
            return l;
//            closeEntityManager();
        }
    }

    public static List<?> findEntities(int maxResults, int firstResult) {
        return findEntities(false, maxResults, firstResult);
    }

    private static List<?> findEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            Query q = em.createQuery("select object(o) from FeedUrl as o");
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            closeEntityManager();
        }
    }

    public static FeedUrl findFeedUrl(Long id) throws NonexistentEntityException, Exception {
        EntityManager em = getEntityManager();
        try {
            return em.find(FeedUrl.class, id);
        } finally {
            closeEntityManager();
        }
    }

    public static int getEntityCount(String entityName) throws NonexistentEntityException, Exception {
        EntityManager em = getEntityManager();
        try {
            return ((Long) em.createQuery("select count(o) from " + entityName + " as o").getSingleResult()).intValue();
        } finally {
            closeEntityManager();
        }
    }

    public static List<FeedUrl> findByTitleLike(String title) throws Exception {
        EntityManager em = getEntityManager();
        List<FeedUrl> fu = new ArrayList<FeedUrl>();
        try {//Executa esta query para buscar pelo título
            Query q = em.createNamedQuery("FeedURL.findByTitleLike");
            q.setParameter("titulo", "%" + title.toUpperCase() + "%");
            fu = (List<FeedUrl>) q.getResultList();
//            fu = (List<FeedUrl>) .setParameter("titulo", title).getResultList();
            //Busca através das tags
            q = em.createNamedQuery("FeedURL.findByTitleByTag");
            q.setParameter("titulo", "%" + title.toUpperCase() + "%");
            fu.addAll((List<FeedUrl>) q.getResultList());
            //Order collection that implements Comparator<FeedUrl>
            Collections.sort(fu);

        } finally {
            return fu;
        }
    }

    public static void mergeFeedTags(FeedUrl fu, ArrayList<Tag> tags) throws Exception {
        EntityManager em = getEntityManager();
        try {
            em.getTransaction().begin();
            FeedUrl fuLocal = (fu.getId() == null ? fu : em.find(FeedUrl.class, fu.getId()));
            if (fuLocal.getId() == null || fuLocal == null) {
                em.persist(fuLocal);
            }
            for (Tag t1 : tags) {
                Scanner sc = new Scanner(t1.getTxt());

                String token = null;
                boolean hasTag = false;
                while (sc.hasNext()) {
                    hasTag = false;
                    token = sc.next().toUpperCase();
                    Tag tag = null;
                    try {
                        tag = (Tag) em.createNamedQuery("Tag.findByTag").setParameter("txt", token).getSingleResult();
                    } catch (Exception e) {
                        tag = new Tag();
                        tag.setTxt(token);
                        em.persist(tag);
                    }

                    for (Tag t2 : fuLocal.getTags()) {
                        if (t2.equals(tag)) {
                            hasTag = true;
                            break;
                        }
                    }
                    if (!hasTag) {
                        fuLocal.getTags().add(tag);
                        em.merge(fuLocal);
                    }
                }
                sc.close();
                sc = null;
            }
            em.getTransaction().commit();
        } catch (Exception e) {
            em.getTransaction().rollback();
            throw e;
        } finally {
            closeEntityManager();
        }
    }
}
